package com.celesea.framework.service;

import com.celesea.framework.dao.BaseDao;
import com.celesea.framework.dao.Filter;
import com.celesea.framework.entity.BaseEntity;
import com.celesea.framework.entity.BusEntity;
import com.celesea.framework.util.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import tk.mybatis.mapper.mapperhelper.EntityHelper;

import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * @param <T>
 * @author Administrator
 */
public abstract class AbstractBaseService<T extends BaseEntity> implements BaseService<T> {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    protected BaseDao<T> baseDao = null;

    protected interface PageProvider<T> {
        Page<T> provider(Filter filter, com.celesea.framework.util.Page page, Sort sort);
    }

    /**
     * 提供到对象
     *
     * @return
     */
    protected BaseDao<T> dao() {
        if (baseDao == null) {
            Class<?> genericClass = GenericsUtils.getSuperClassGenricType(this.getClass());
            String className = genericClass.getName();
            className = className.replace("entity", "dao") + "Dao";
            try {
                @SuppressWarnings("unchecked")
                Class<? extends BaseDao<T>> daoClass =
                        (Class<? extends BaseDao<T>>) Class.forName(className);
                baseDao = SpringContextHolder.getBean(daoClass);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(String.format("类【%s】获取Dao接口失败", className));
            }
        }
        return baseDao;
    }

    @Override
    @SuppressWarnings("unchecked")
    public T selectForNew() {
        Class<T> genericClass = GenericsUtils.getSuperClassGenricType(this.getClass());
        String className = genericClass.getName();
        try {
            Class<T> modelClass = (Class<T>) Class.forName(className);
            return modelClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(String.format("类【%s】获取Model失败", className));
            return null;
        }
    }

    @Override
    public T selectById(String id) {
        Assert.notNull(id, "查询对象不能为空");
        T result = dao().selectByPrimaryKey(id);
        Assert.notNull(result, String.format("数据对象【%s】不存在", id));
        return result;
    }

    @Override
    public T selectForView(String id) {
        return selectById(id);
    }

    @Override
    public T doSave(T entity) {
        if (isInsert(entity)) {
            return insert(entity);
        } else {
            return update(entity);
        }
    }

    private T beforeInsert(T entity) {
        if (entity instanceof BusEntity) {
            BusEntity busEntity = (BusEntity) entity;
            busEntity.insertInfo();
        }
        generatPk(entity);
        return entity;
    }

    @Override
    public T insert(T entity) {
        int result = 0;
        beforeInsert(entity);
        result = dao().insert(entity);
        if (result == 0) {
            throw new RuntimeException("保存失败，请重试！");
        }
        return entity;
    }

    @Override
    public int insertList(List<T> entitys) {
        Assert.notEmpty(entitys, "数据对象不能为空！");
        entitys.stream().forEach(item -> beforeInsert(item));
        int result = dao().insertList(entitys);
        Assert.isTrue(result == entitys.size(), "批量保存操作失败！");
        return result;
    }

    @Override
    public T update(T entity) {
        int result = 0;
        // 业务属性逻辑处理
        if (entity instanceof BusEntity) {
            BusEntity busEntity = (BusEntity) entity;
            busEntity.updateInfo();
            Example example = new Example(entity.getClass());
            Criteria criteria1 = example.createCriteria();
            criteria1.andEqualTo(BaseEntity.PK, entity.getId())
                    .andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId());
//            Version version = com.celesea.framework.entity.getClass().getAnnotation(Version.class);
//            if (version != null) {
//                criteria1.andEqualTo(BusEntity.VERSION, busEntity.getVersion());
//                busEntity.incrementVersion();
//            }
            result = dao().updateByExampleSelective(entity, example);
        } else {
            result = dao().updateByPrimaryKey(entity);
        }
        if (result == 0) {
            throw new RuntimeException("保存失败，请重试！");
        }
        return entity;
    }

    protected Example buildUpdateByPkExample(T entity) {
        Example example = new Example(entity.getClass());
        Criteria criteria1 = example.createCriteria();
        criteria1.andEqualTo(BaseEntity.PK, entity.getId()).andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId());
        return example;
    }

    @Override
    public int updateByExample(T entity) {
        Example example = buildUpdateByPkExample(entity);
        entity.setId(null);
        entity.setTenantId(null);
        int result = dao().updateByExample(entity, example);
        return result;
    }

    @Override
    public int updateByExampleSelective(T entity) {
        Example example = buildUpdateByPkExample(entity);
        entity.setId(null);
        entity.setTenantId(null);
        int result = dao().updateByExampleSelective(entity, example);
        return result;
    }

    @Override
    public boolean checkUnique(T entity) {
        T result = selectUnique(entity);
        if (result == null) {
            return true;
        } else {
            return result.getId().equals(entity.getId());
        }
    }

    @Override
    public T selectUnique(T entity) {
        Class<?> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());
        try {
            Example example = new Example(entityClass);
            Criteria criteria = example.createCriteria();
            // 获取全部列
            Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
            // 当某个列有主键策略时，不需要考虑他的属性是否为空，因为如果为空，一定会根据主键策略给他生成一个值
            for (EntityColumn column : columnList) {
                if (column.isId()) {
                    continue;
                }
                String property = column.getProperty();
                Object value = BeanUtils.getProperty(entity, property);
                if (value != null) {
                    criteria.andEqualTo(property, value);
                }
            }
            List<T> result = dao().selectByExample(example);
            if (CollectionKit.isEmpty(result)) {
                return null;
            } else {
                return result.get(0);
            }
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
            return null;
        }
    }

    @Override
    public PageData<T> selectPage(Filter filter, com.celesea.framework.util.Page page, Sort sort) {
        return selectPageData(filter, page, sort, new PageProvider<T>() {

            @Override
            public Page<T> provider(Filter filter, com.celesea.framework.util.Page page, Sort sort) {
                return (Page<T>) dao().selectPage(filter, page, sort);
            }
        });
    }

    protected PageData<T> selectPageData(Filter filter,
                                         com.celesea.framework.util.Page page,
                                         Sort sort,
                                         PageProvider<T> provider) {
        PageData<T> data = new PageData<T>();
        // 分页
        if (page != null && page.isCountPage()) {
            PageHelper.startPage(page.getCurrent(), page.getPageSize(), true);
        }
        // 排序
        if (sort != null && sort.isSort()) {
            PageHelper.orderBy(sort.toSort());
        }

        Page<T> pages = provider.provider(filter, page, sort);
        data.setDataList(pages.getResult());
        data.setPager(page.toPager(pages.getTotal()));
        data.setFilter(filter);
        data.setSort(sort);
        return data;
    }

    @Override
    public List<T> selectList(Filter filter, Sort sort) {
        // 排序
        if (sort != null && sort.isSort()) {
            PageHelper.orderBy(sort.toSort());
        }
        return dao().selectPage(filter, null, sort);
    }

    @Override
    public List<T> selectList(Filter filter) {
        return this.selectList(filter, null);
    }

    @Override
    public List<T> selectAll() {
        return dao().selectAll();
    }

    @Override
    public void doDelete(List<String> ids) {
        if (CollectionKit.isNotEmpty(ids)) {
            for (String id : ids) {
                doDelete(id);
            }
        }
    }

    @Override
    public void doRemove(List<String> ids) {
        if (CollectionKit.isNotEmpty(ids)) {
            for (String id : ids) {
                doRemove(id);
            }
        }
    }

    @Override
    public int doRemove(String id) {
        doRemoveMapping(id);
        return dao().deleteByPrimaryKey(id);
    }

    @Override
    public int doDelete(String id) {
        doDeleteMapping(id);
        T entity = selectForNew();
        entity.setId(id);
        BusEntity busEntity = (BusEntity) entity;
        busEntity.delete();
        int result = updateByExampleSelective(entity);
        Assert.isTrue(result > 0, "删除失败！");
        return result;
    }


    @Override
    public void doRemoveMapping(String id) {

    }

    @Override
    public void doDeleteMapping(String id) {

    }

    @Override
    public T generatPk(T entity) {
        if (StringKit.isEmpty(entity.getId())) {
            entity.setId(generatPk());
        }
        return entity;
    }

    @Override
    public String generatPk() {
        return UUID.randomUUID().toString();
    }

    /**
     * 检查是否插入数据
     *
     * @param model
     * @return
     */
    protected boolean isInsert(BaseEntity model) {
        return StringKit.isEmpty(model.getId());
    }

    /**
     * 是否更新
     *
     * @param model
     * @return
     */
    protected boolean isUpdate(BaseEntity model) {
        return !isInsert(model);
    }


}
